Your code pretty and healthy

We all already had (or, at least, will have) the experience of getting to work with someone's piece of code and find it a nightmare to make it run, install, debug, etc. Sometimes this someone is our Past Selves that did not do a good job writing a code thinking that someday someone would need to use it.

If one writes a code that it is not easy to install, easy to run, easily read and easily debuged, the chances that this code falls in the void are very high. Even when we are sure that we will be the only ones that will use this piece of code, if we don't do it properly the chances that we will have to write the code again are also very high.

There are a lot of people (and probably the reader is one of these) that think that a readable-well-documented code is important but does not actually write codes like that, because... well... you know... it is just a draft of a script... I will use it only once... and I do not want to waste time writing more lines to make it clearer.

Well, my friend. If you do not dedicate more time to make a good code, you will have to make it twice. Or three times. Or maybe four times. So where are you actually wasting your time?

I did a quick research to investigate what people would think it is the most critical to maintain some code or piece of code alive, pretty and healthy. The results are shown bellow:

So most people actually do think it is more important to have codes

  1. With good documentation
  2. That can be read easily

But most people simply do not write code like that and my question is: Why?

Python was developed for fast development. It is not a very efficient language if one thinks in terms of computational processing but it is much faster to write a code and implement an idea in Python than in any other language. Python was also created thinking on sharing this ideas so why people are still not writing clear codes? Why people still waste their time writing and repeating and re-inventing the wheel when there are tons of codes around there?

If, at least, one of the reasons is because they simply does not know how to do it. Before actually seeing how to do it, let us open our terminals and pray the "Zen of Phython". If you never read it, read it. Now. 10 times. Really.

The Zen of Python

The Zen of Python can be easily found on Google but the actual easiest way to find it for reference is simply opening a terminal, typing python or ipython and then write import this.


In [1]:
import this


The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

This is almost like poetry but it is how we should be writing our codes. And you know what? It is EASY! This notebook will have a quick overview of how to add docstrings and comments to your code and how to write a clear code.

Do the docstring for your life

It is absurdely simple to add docstrings to your python code. That can be done in the beggining of a file or after the definition of a method/function or class. Let me show you some examples.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
My Sample Code

This is such a simple documentation! The only thing I have to do 
is to add three single quotes (') or double quotes (") together to 
start a docstring block! Then just write down in a few words what
you want to do in your file.

by J. Bond - Feb 31, 202X
"""

And there you go! You added documentation! Yay!

You can do that also if you have the definition of a method.


In [8]:
def say_hello(name):
    """
    This method simply says hello to the person whose name is given 
    as parameter.
    """
    print "Hello, {0}!".format(name)

In [9]:
say_hello("Bruno")


Hello, Bruno!

And if I need to get some more information about this function, I can write:


In [11]:
help(say_hello)


Help on function say_hello in module __main__:

say_hello(name)
    This method simply says hello to the person whose name is given 
    as parameter.

There are different documentation standards that you or your group may choose to use. The important thing here is to make sure that Sphinx can read it and process it so you are saving your time. Really.

Here are two examples of documentation standards that I already used:

PEP252 DocString Standard


In [13]:
def say_hello(name):    
    """    
    This method simply says hello to the person 
    whose name is given as parameter.

    param name: the name of the person that will be greeted.
    ptype name: string    
    """    
    print "Hello, {0}!".format(name)

This documentation standard is called PEP 252 and can be found here.

Google DocString Standard


In [14]:
def say_hello(name):    
    """    
    This method simply says hello to the person 
    whose name is given as parameter.

    Parameters
    ----------
        name: string
        The name of the person that will be greeted.
    """    
    print "Hello, {0}!".format(name)

This is how Google has been used to document their codes and it is also read by Sphinx. You can find more about this style here. The final choice is yours to do but you want to make sure you are the clearest possible.

Why write if others can’t read?

People that work with Python are worried about code readability. That is so true that a document called PEP-8 was written in order to help mortals to get their code clearer and easier to read. The full document is quite short and easy to read and it can be found here. Here are some examples.

Language

It may be very tempting to write comments and documentation in your mother language. But if you are not 10000000% sure that your code will be used by people that speak it, write them in English.

Identation

According to PEP-8, one should always use space instead of usig tabs. The recommended identation size is 4 spaces. This avoid errors when messing up with both identation methods. Just search over the Internet how to setup your favorite editor to keep the identation method always the same (hopefully 4 spaces).


In [37]:
for i in range(10):
	x = i * 2
    print x


  File "<ipython-input-37-caabfb8f1cf7>", line 3
    print x
           ^
IndentationError: unindent does not match any outer indentation level

Do a proper name

Look the following method definition:

  1. Muti-word variables and methods should be lower-case and separated by underscore. Ex:

     number_of_states = 5
    
     def sum_integers(x, y):
         return (x, y)
  2. Classes can follow CamelCase notation:

     class PhaseMap:
         def __init__(self, **kwargs):
             self.input_filename = kwargs['filename']

Re-using files

I already had the terrible experience of getting to codes where it is simply impossible to track down where the variables come from. Ok, not impossible. But rearly there. At least considering the time that I had to look into those codes.

I ended up not using them simply because the way that the author was importing files was giving me no clue about where I could find the definition of functions, classes, etc. Here is an example. Consider you have a file called file_1.py


In [33]:
# file_1.py
x = 10
y = 20

Now I want to use x and y(or probably something much more complicated that I do not want to write again). Here is one way that I can re-use my existing file:


In [40]:
from file_1 import *
print x + y


30

Ok. That is easy. But what if my code has hundreds of lines and what if I imported four files instead of one?


In [41]:
from file_1 import *
from file_2 import *
print a + x


11

Three lines. Two files. And we are already screwed. Please, be a nice person and just do a proper import so the reader know what is going on.


In [44]:
# file_2.py
import file_1 
import file_2
print file_1.x + file_2.a + file_1.y


31

In [ ]: